import Vue from "vue";

export const INPUT_MODE = ["T9", "ABC", "123"];
const SETTINGS_KEYS = {
    T9_ENABLED: "keypad.t9-enabled",
    WORD_SUGGESTION: "keypad.wordsuggestion",
    EN_US: "keypad.layouts.english_us",
    ZH_CN: "keypad.layouts.chinese_cn",
    ACTIVE_LAYOUT: "keypad.active-layout",
    ACTIVE_MODE: "keypad.active-mode",
};

const INPUT_MODE_PINYIN = "T9";
const INPUT_MODE_123 = "123";
const INPUT_MODE_ABC = "ABC";

const saveSettings = (key, value) => {
    var lock = navigator.mozSettings.createLock();
    var setting = {};
    setting[key] = value;
    lock.set(setting);
};

const stashSettings = (key, value, option) => {
    if (option && option.save) {
        saveSettings(key, value);
    }
};

export const setActiveLayout = (layout) => {
    if (__DEV__) {
        return;
    }
    stashSettings(SETTINGS_KEYS.ACTIVE_LAYOUT, layout, { save: true });
};
const setActiveMode = (mode) => {
    if (__DEV__) {
        return;
    }
    stashSettings(SETTINGS_KEYS.ACTIVE_MODE, mode, { save: true });
};

const isDigit = (aChar) => /^\d$/.test(aChar);

const NUMBER_KEYS = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "*", "0", "#"];
const ARROW_KEYS = ["ArrowUp", "ArrowRight", "ArrowDown", "ArrowLeft"];
const FUNCTION_KEYS = ["SoftLeft", "SoftRight", "Enter", "Backspace"];
const isNumberKey = function (key) {
    return NUMBER_KEYS.indexOf(key) > -1;
};
const isArrowKey = function (key) {
    return ARROW_KEYS.indexOf(key) > -1;
};
const isFunctionKey = function (key) {
    return FUNCTION_KEYS.indexOf(key) > -1;
};

const convertKeyToKeyCode = function (key) {
    switch (key) {
        case "ArrowRight":
        case "ArrowLeft":
            key = key.split("Arrow")[1].toUpperCase();
            break;
        case "Backspace":
            key = "BACK_SPACE";
            break;
        case "Enter":
            key = "RETURN";
            break;
        default:
            break;
    }
    return KeyboardEvent["DOM_VK_" + key];
};

type KeyValue = (helper: KeypadHelper, e: KeyboardEvent,) => void;

interface Keys {
    SoftLeft?: KeyValue,
    Enter?: KeyValue,
    SoftRight?: KeyValue,
    Backspace?: KeyValue,
    ArrowUp?: KeyValue,
    ArrowDown?: KeyValue,
    ArrowLeft?: KeyValue,
    ArrowRight?: KeyValue,
    Up?: KeyValue,
    Down?: KeyValue,
    Left?: KeyValue,
    Right?: KeyValue,
    [key: string]: KeyValue | undefined,
}

type EventType = "keyDown" | "keyUp" | "keyPress" | "keyLongPress";

export interface ABC {
    key: string;
    timer: any;
    index: number;
    items: string[];
}

export type Events = {};
export type Data = {
    inputMode: string,
    abc: ABC | null,
    composition: string,
    rootList: any[] | null,
    rootIndex: number,
    wordsList: any[] | null,
    toBeIndex: number,
    adaptor: any,
};

const CharKeys: { [key: string]: string } = {
    1: ".,?!;:/@-+_=",
    0: " 0",
    "*": `"()[]<>{}`,
}
const PinyinKeys: { [key: string]: string } = {
    2: 'abc', 3: 'def',
    4: 'ghi', 5: 'jkl', 6: 'mno',
    7: 'pqrs', 8: 'tuv', 9: 'wxyz',
}

const isInputContextNative = (e) => {
    return e.target?.["inputMode"] == "native";
}

class KeypadHelper {
    inputMode!: string;
    keyEvents: {
        key: string,
        timer: any;
    }[] = [];
    events!: Events//{ [P in EventType]?: Keys; };
    inputContext: any;
    isDefaultSoftkeyBar: any;
    isComposing = false;
    data!: Data;

    // groupList: any[] = [];
    // mayList: any[] = [];
    // minorList: any[] = [];
    // inputVal = "";
    // may = {
    //     list: [''],
    //     index: '',
    //     children: false
    // };
    // isGrouping: any = null;
    context: Vue;

    constructor(options: { context: Vue, inputContext: any, data: Data }) {
        this.context = options.context;
        this.data = options.data;
        this.inputMode = options.data.inputMode;
        if (__DEV__) {
            document.addEventListener("keydown", (e) => {
                this.onKeyDown(e);
            });
            document.addEventListener("keyup", (e) => {
                this.onKeyUp(e);
            });
            this.data = options.data;
            this.activeInputMode();
            return;
        }
        this.inputContext = options.inputContext;
        this.isDefaultSoftkeyBar = options.inputContext.defaultSoftkeyBar || !options.inputContext.isFromApp;
        this.inputContext.addEventListener("keydown", (e) => {
            // if (isInputContextNative(e)) {
            //     return
            // }
            e["key"] = e.detail.key;
            e["keyCode"] = e.detail.keyCode;
            this.onKeyDown(e);
        });
        this.inputContext.addEventListener("keypress", (e) => {
            // if (isInputContextNative(e)) {
            //     return
            // }
            // this.onKey(e, "press", e.detail.key, e.target);
            e.preventDefault();
            e.stopImmediatePropagation();
        });
        this.inputContext.addEventListener("keyup", (e) => {
            // if (isInputContextNative(e)) {
            //     return
            // }
            e["key"] = e.detail.key;
            e["keyCode"] = e.detail.keyCode;
            this.onKeyUp(e);
        });
        this.activeInputMode();
        // window.resizeTo(0, 0);
        // this.events = events;
    }

    onKeyDown(e: KeyboardEvent) {
        if (!e.repeat) {
            let t = setTimeout(() => {
                clearTimeout(t);
                this.keyEvents.splice(this.keyEvents.findIndex(o => o.key == e.key), 1)
                this.on("keyLongPress", e);
            }, 500);
            this.keyEvents.push({
                key: e.key,
                timer: t,
            })
            this.on("keyDown", e);
        }
    }

    onKeyUp(e: KeyboardEvent) {
        this.on("keyUp", e);
        let key = this.keyEvents.splice(this.keyEvents.findIndex(o => o.key == e.key), 1);
        if (key.length) {
            clearTimeout(key[0].timer);
            this.on("keyPress", e);
        }
    }

    on(eventType: EventType, e: KeyboardEvent) {
        // console.log(eventType, e);
        // inputContext.setComposition("黄鸡");
        // inputContext.endComposition("黄鸡");
        // let event = this.events?.[eventType];
        // if (!event) {
        //     return;
        // }
        // if (e.key in event) {
        //     event[e.key]?.(this, e);
        // }

        let key = e.key;
        let keyCode = e.keyCode;
        switch (key) {
            case "EndCall":
            case "F12":
            case "SoftLeft":
            case "SoftRight":
                return;
            case "ArrowDown":
            case "ArrowUp":
            case "ArrowLeft":
            case "ArrowRight":
            case "Enter":
                if (eventType == "keyDown" && this.isPinyin()) {
                    e.preventDefault();
                    e.stopImmediatePropagation();
                }
                break;
            case "Backspace":
                if (eventType == "keyDown") {
                    e.preventDefault();
                    e.stopImmediatePropagation();
                }
                break;
            default:
                break;
        }
        if (eventType === "keyDown") {
            if (this.inputMode == INPUT_MODE_ABC) {
                if (key >= "a" && key <= "z") {
                    this.addText(key);
                    return;
                }
            }
            switch (key) {
                case "ArrowLeft":
                    this.addIndex(-1);
                    break;
                case "ArrowRight":
                    this.addIndex(1);
                    break;
                case "Backspace":
                    this.clearWord();
                    break;
            }
        } else if (eventType === "keyPress") {
            if (this.inputMode == INPUT_MODE_123) {
                if (key >= "0" && key <= "9") {
                    this.addText(key);
                    return;
                }
            } else if (this.inputMode == INPUT_MODE_PINYIN) {
                if (key == "0") {
                    if (!this.onEnter()) {
                        this.abc(key);
                    }
                    return;
                } else if (key == "1") {
                    if (!this.isPinyin()) {
                        this.abc(key);
                    }
                    return;
                } else if (key >= "2" && key <= "9") {
                    // this.groupList.push(PinyinKeys[key].split(""));
                    // this.data.composition += key;
                    // this.onChange_GroupList(false);
                    this.setLetter(keyCode);
                    return;
                } else if (key >= "a" && key <= "z") {
                    return;
                }
            } else if (this.inputMode == INPUT_MODE_ABC) {
                if (key >= "0" && key <= "9") {
                    this.abc(key);
                    return;
                }
            }
            switch (key) {
                case "ArrowUp":
                    this.addRootIndex(-1);
                    break;
                case "ArrowDown":
                    this.addRootIndex(1);
                    break;
                case " ":
                case "Enter":
                    if (!this.onEnter()) {
                        this.sendKey(key);
                    }
                    break;
                case "*":
                    if (this.isPinyin()) {

                    } else {
                        this.abc(key);
                    }
                    break;
                case "#":
                    if (this.isPinyin()) {

                    } else {
                        this.nextInputMode();
                    }
                    break;
            }
        } else if (eventType === "keyLongPress") {
            if (this.inputMode == INPUT_MODE_PINYIN || this.inputMode == INPUT_MODE_ABC) {
                if (key >= "0" && key <= "9") {
                    this.addText(key);
                    return;
                }
            }
            switch (key) {
                case "Backspace":
                    this.clearAllText();
                    break;
                case "*":
                    // this.handleMenu();
                    break;
                case "#":

                    break;
            }
        }
    }


    activeInputMode() {
        setActiveMode({ mode: this.inputMode, byUser: false });
    }

    nextInputMode() {

        // switch (inputContext.inputType) {
        //     case "text":
        //         break;
        // }
        let index = INPUT_MODE.indexOf(this.inputMode);
        if (index == -1) {
            index = 0;
        } else {
            index++;
            if (index >= INPUT_MODE.length) {
                index = 0;
            }
        }
        this.inputMode = INPUT_MODE[index];
        this.data.inputMode = this.inputMode;
        this.activeInputMode();
        console.log("nextInputMode", this.inputMode);
    };

    sendKey(key: string) {
        if (!this.inputContext) {
            return;
        }
        var keyCode = convertKeyToKeyCode(key);
        if (keyCode) {
            switch (keyCode) {
                case KeyboardEvent["DOM_VK_BACK_SPACE"]:
                    this.inputContext.sendKey(KeyboardEvent["DOM_VK_BACK_SPACE"], 0, 0, false);
                    break;
                case KeyboardEvent["DOM_VK_LEFT"]:
                case KeyboardEvent["DOM_VK_RIGHT"]:
                    this.inputContext.sendKey(keyCode, 0, 0);
                    break;
                case KeyboardEvent["DOM_VK_RETURN"]:
                    this.inputContext.sendKey(KeyboardEvent["DOM_VK_RETURN"], 0, 0, false);
                    break;
                default:
                    this.inputContext.sendKey(0, keyCode, 0);
                    break;
            }
        } else {
            if (key === "SoftRight" && this.isDefaultSoftkeyBar) {
                navigator.mozInputMethod.mgmt.hide();
            }
        }
    };

    isInputContextEmpty() {
        var textLength = this.inputContext.textBeforeCursor.length + this.inputContext.textAfterCursor.length;
        var isEmptyNewline = textLength === 1 && this.inputContext.textAfterCursor === "\n";
        var isInputContextEmpty = textLength === 0 || isEmptyNewline;
        return isInputContextEmpty;
    };

    deleteText() {
        if (__DEV__) {
            console.log("deleteText");
            return;
        }
        if (this.inputContext.textBeforeCursor.length > 0) {
            if (this.inputContext.deleteBackward) {
                this.inputContext.deleteBackward();
            } else {
                this.inputContext.deleteSurroundingText(-1, 1);
            }
        }
    };

    clearAllText() {
        console.log("clearAllText");
        if (this.data.composition.length) {
            this.reset();
        } else if (this.inputContext) {
            navigator.mozInputMethod.clearAll();
        }
    };



    addText(char: string) {
        if (__DEV__) {
            console.log("addText:", char);
            return;
        }
        if (!this.inputContext) {
            return;
        }
        this.inputContext.setComposition(char);
        this.inputContext.endComposition(char);
    }

    abc(key: string) {
        if (this.data.abc) {
            if (this.data.abc.key == key) {
                this.data.abc.index++;
                clearTimeout(this.data.abc.timer);
                this.data.abc.timer = setTimeout(() => {
                    this.addABC();
                }, 500);
                return;
            }
            this.addABC();
        }
        let keys = PinyinKeys[key];
        let isPinyin = !!keys;
        if (!keys) {
            keys = CharKeys[key];
        }
        if (!keys) {
            return;
        }
        this.data.abc = {
            key,
            timer: setTimeout(() => {
                this.addABC();
            }, 500),
            index: 0,
            items: isPinyin ? [...keys.split(""), ...keys.toUpperCase().split(""),] : keys.split(""),
        }
    }

    addABC() {
        if (!this.data.abc) {
            return;
        }
        clearTimeout(this.data.abc.timer);
        this.addText(this.data.abc.items[this.data.abc.index % this.data.abc.items.length]);
        this.data.abc = null;
    }

    addWord(item) {
        // this.groupList = this.groupList.slice(item.index.length, this.inputVal.length);
        // this.inputVal = this.inputVal.slice(item.index.length, this.inputVal.length);
        // this.data.composition = this.inputVal;

        item && this.addText(item.word);
        // this.onChange_GroupList();
        this.reset();
    }

    clearWord() {
        if (this.isPinyin()) {
            this.setLetter(KeyboardEvent["DOM_VK_BACK_SPACE"]);
        } else {
            this.onDelete();
        }
        // if (!this.inputVal.length) {
        //     this.onDelete();
        // } else {
        //     this.groupList = this.groupList.slice(0, this.groupList.length - 1) || [];
        //     this.inputVal = this.inputVal.slice(0, this.inputVal.length - 1);
        //     this.data.composition = this.inputVal;
        //     this.onChange_GroupList(false);
        // }
    }

    onDelete() {
        this.deleteText();
        // if (this.mIndex - 1 >= 0) {
        //     this.mItems.splice(this.mIndex - 1, 1);
        //     this.mIndex -= 1
        // }
    }

    isPinyin() {
        return !!this.data.composition.length;
    }

    onEnter() {
        if (this.isPinyin()) {
            this.addWord(this.data.wordsList![this.data.toBeIndex]);
            return true;
        }
        return false;
    }

    addIndex(value: number) {
        let charCount = this.data.wordsList?.length;
        if (charCount) {
            if (this.data.toBeIndex + value >= 0 && this.data.toBeIndex + value < charCount) {
                this.data.toBeIndex += value;
            }
        } else if (!this.isPinyin()) {
            if (this.inputContext) {
                if (value > 0) {
                    this.inputContext.sendKey(KeyboardEvent["DOM_VK_RIGHT"], 0, 0);
                } else if (value < 0) {
                    this.inputContext.sendKey(KeyboardEvent["DOM_VK_LEFT"], 0, 0);
                }
            }
        }
    }

    addRootIndex(value: number) {
        switch (value) {
            case 1:
                this.data.adaptor.setLetter(224, KeyboardEvent["DOM_VK_RIGHT"]);
                this.refreshData();
                break;
            case -1:
                this.data.adaptor.setLetter(224, KeyboardEvent["DOM_VK_LEFT"]);
                this.refreshData();
                break;
        }
    }

    setLetter(keyCode: number) {
        this.data.adaptor.setLetter(0, keyCode);
        if (this.data.adaptor.myCandidates.data.a.length == 0) {
            if (KeyboardEvent["DOM_VK_BACK_SPACE"] != keyCode) {
                this.data.adaptor.setLetter(0, KeyboardEvent["DOM_VK_BACK_SPACE"]);
            }
        }
        this.refreshData();
    }

    refreshData() {
        let data = this.data.adaptor.myCandidates.data;
        if (data.a.length) {
            this.data.rootIndex = data.index;
            this.data.rootList = data.a;
            this.data.composition = this.data.rootList![this.data.rootIndex];
            this.data.rootList = data.a;
            this.data.wordsList = data.b.map(o => {
                return {
                    word: o,
                }
            });
            this.data.toBeIndex = 0;
        } else {
            this.data.composition = "";
            this.data.rootList = null;
            this.data.rootIndex = -1;
            this.data.wordsList = null;
            this.data.toBeIndex = -1;
        }
    }

    reset() {
        this.data.adaptor.reset();
        this.refreshData();
    }

    handleMenu() {
        this.context.$prompt.showDialog_List({
            title: "文字编辑",
            data: [
                {
                    label: "选择",
                    click: () => {

                    },
                },
                {
                    label: "全选",
                    click: () => {

                    },
                },
                {
                    label: "复制",
                    click: () => {

                    },
                },
                {
                    label: "剪切",
                    click: () => {

                    },
                },
                {
                    label: "粘贴",
                    click: () => {

                    },
                },
            ]
        }, (item, index) => {
            item.click();
        });
    }

}

export default KeypadHelper;